package fixtures

import (
	vtTimestamppb "github.com/planetscale/vtprotobuf/types/known/timestamppb"
	"github.com/stackrox/rox/generated/storage"
	"github.com/stackrox/rox/pkg/protocompat"
	"github.com/stackrox/rox/pkg/uuid"
	"google.golang.org/protobuf/types/known/timestamppb"
)

// GetGlobalDeferralRequest returns a mock pending deferral request with global scope for specified CVE
func GetGlobalDeferralRequest(cves ...string) *storage.VulnerabilityRequest {
	scope := &storage.VulnerabilityRequest_Scope{
		Info: &storage.VulnerabilityRequest_Scope_GlobalScope{GlobalScope: &storage.VulnerabilityRequest_Scope_Global{}},
	}
	req := getVulnRequest(storage.VulnerabilityState_DEFERRED, scope, cves...)

	req.Req = &storage.VulnerabilityRequest_DeferralReq{
		DeferralReq: &storage.DeferralRequest{
			Expiry: &storage.RequestExpiry{
				Expiry: &storage.RequestExpiry_ExpiresOn{ExpiresOn: protocompat.TimestampNow()},
			},
		},
	}
	return req
}

// GetImageScopeDeferralRequest returns a mock pending deferral request with an image scope for specified CVE
func GetImageScopeDeferralRequest(registry, remote, tag string, cves ...string) *storage.VulnerabilityRequest {
	req := getVulnRequest(storage.VulnerabilityState_DEFERRED, getImageScope(registry, remote, tag), cves...)

	req.Req = &storage.VulnerabilityRequest_DeferralReq{
		DeferralReq: &storage.DeferralRequest{
			Expiry: &storage.RequestExpiry{
				Expiry: &storage.RequestExpiry_ExpiresOn{ExpiresOn: protocompat.TimestampNow()},
			},
		},
	}
	return req
}

// GetGlobalFPRequest returns a mock pending FP request with global scope for specified CVE
func GetGlobalFPRequest(cves ...string) *storage.VulnerabilityRequest {
	scope := &storage.VulnerabilityRequest_Scope{
		Info: &storage.VulnerabilityRequest_Scope_GlobalScope{GlobalScope: &storage.VulnerabilityRequest_Scope_Global{}},
	}
	req := getVulnRequest(storage.VulnerabilityState_FALSE_POSITIVE, scope, cves...)
	req.Req = &storage.VulnerabilityRequest_FpRequest{FpRequest: &storage.FalsePositiveRequest{}}
	return req
}

// GetImageScopeFPRequest returns a mock pending FP request with an image scope for specified CVE
func GetImageScopeFPRequest(registry, remote, tag string, cves ...string) *storage.VulnerabilityRequest {
	req := getVulnRequest(storage.VulnerabilityState_FALSE_POSITIVE, getImageScope(registry, remote, tag), cves...)
	req.Req = &storage.VulnerabilityRequest_FpRequest{FpRequest: &storage.FalsePositiveRequest{}}
	return req
}

// GetApprovedDeferralRequest returns a mock image scoped deferral request that has been approved with fake comments, requestors and approvers
func GetApprovedDeferralRequest(registry, remote, tag string, cves ...string) *storage.VulnerabilityRequest {
	req := GetImageScopeDeferralRequest(registry, remote, tag, cves...)
	req.Status = storage.RequestStatus_APPROVED
	req.Approvers = []*storage.SlimUser{{
		Id:   "id-approver",
		Name: "fake-approver",
	}}
	req.Comments = append(req.Comments, &storage.RequestComment{
		Id:        uuid.NewV4().String(),
		Message:   "this is a mock comment by the approver",
		User:      req.GetApprovers()[0].CloneVT(),
		CreatedAt: (*timestamppb.Timestamp)((*vtTimestamppb.Timestamp)(req.GetCreatedAt()).CloneVT()),
	})
	return req
}

// GetGlobalDeferralRequestV2 returns a mock pending deferral request with global scope according to the v2 representation for specified CVE.
func GetGlobalDeferralRequestV2(cves ...string) *storage.VulnerabilityRequest {
	scope := getImageScope(".*", ".*", ".*")
	req := getVulnRequest(storage.VulnerabilityState_DEFERRED, scope, cves...)
	req.Req = &storage.VulnerabilityRequest_DeferralReq{
		DeferralReq: &storage.DeferralRequest{
			Expiry: &storage.RequestExpiry{
				Expiry: &storage.RequestExpiry_ExpiresOn{ExpiresOn: protocompat.TimestampNow()},
			},
		},
	}
	return req
}

// GetGlobalFPRequestV2 returns a mock pending FP request with global scope according to the v2 representation for specified CVE.
func GetGlobalFPRequestV2(cves ...string) *storage.VulnerabilityRequest {
	scope := getImageScope(".*", ".*", ".*")
	req := getVulnRequest(storage.VulnerabilityState_FALSE_POSITIVE, scope, cves...)
	req.Req = &storage.VulnerabilityRequest_FpRequest{FpRequest: &storage.FalsePositiveRequest{}}
	return req
}

func getImageScope(registry, remote, tag string) *storage.VulnerabilityRequest_Scope {
	return &storage.VulnerabilityRequest_Scope{
		Info: &storage.VulnerabilityRequest_Scope_ImageScope{
			ImageScope: &storage.VulnerabilityRequest_Scope_Image{
				Registry: registry,
				Remote:   remote,
				Tag:      tag,
			},
		},
	}
}
func getVulnRequest(state storage.VulnerabilityState, scope *storage.VulnerabilityRequest_Scope, cves ...string) *storage.VulnerabilityRequest {
	now := protocompat.TimestampNow()
	requestor := &storage.SlimUser{
		Id:   uuid.NewV4().String(),
		Name: "thisisaname",
	}

	return &storage.VulnerabilityRequest{
		Id:          uuid.NewV4().String(),
		Name:        uuid.NewV4().String(),
		TargetState: state,
		Status:      storage.RequestStatus_PENDING,
		Requestor:   requestor,
		CreatedAt:   now,
		LastUpdated: now,
		Scope:       scope,
		Entities: &storage.VulnerabilityRequest_Cves{
			Cves: &storage.VulnerabilityRequest_CVEs{
				Cves: cves,
			},
		},
		Comments: []*storage.RequestComment{{
			Id:        uuid.NewV4().String(),
			Message:   "this is a mock comment by the requestor",
			User:      requestor.CloneVT(),
			CreatedAt: now,
		}},
	}
}
